package com.hllxd.hism.passport.login.gateway.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hllxd.hism.passport.login.gateway.dao.redis.AccessTokenRedisMapper;
import com.hllxd.hism.passport.login.gateway.exception.BusinessException;
import com.hllxd.hism.passport.login.gateway.controller.LogOnQRCodeResult;
import com.hllxd.hism.passport.login.gateway.dao.http.SmsVpcMapper;
import com.hllxd.hism.passport.login.gateway.dao.mapper.mis.UserMapper;
import com.hllxd.hism.passport.login.gateway.dao.redis.AuthorityRedisMapper;
import com.hllxd.hism.passport.login.gateway.model.*;
import com.hllxd.hism.passport.login.gateway.util.TimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

/**
 * 发送短信
 * @author lixiyong
 * @date 2020-05-12 15:47
 */
@Slf4j @Service public class PassportServiceImpl implements PassportService {
    private static final Logger logger = LoggerFactory.getLogger(PassportServiceImpl.class);
    @Autowired private AccessTokenRedisMapper accessTokenRedisMapper2;

    @Autowired private AuthorityRedisMapper authorityRedisMapper;

    @Autowired private UserMapper userMapper;

    @Autowired private SmsVpcMapper smsVpcMapper;


    final String CODE_TAG="code";
    final String SUCCESS_CODE = "000";
    final String DEFAULT_PASSWORD="000000";

    /**
     * 测试账号
     */
    private static Set<String> numbers;
    static {
        numbers = new HashSet<>();
        numbers.add("13811834706");
        // 对外提供验证码
        numbers.add("18866668888");
        numbers.add("lixiyong01");
    }
    final String TESTER_PASSWORD = "000000";
    /**
     * 测试OA账号
     */
    private static Set<String> os_names;
    static {
        os_names = new HashSet<>();
        os_names.add("lixiyong01");
        os_names.add("test_weixin");
    }

    @Override public DynamicCodeResponse sendDynamicCode(DynamicCodeRequest req) {
        Integer plat = req.getPlat();
        String phoneNumber = req.getPhoneNumber();
       return sendDynamicCode(phoneNumber, plat);
    }

    @Override public DynamicCodeResponse sendDynamicCode(String phoneNumber, Integer plat) {
        DynamicCodeResponse response = new DynamicCodeResponse();
        UserEntity user = getUserFromPhone(phoneNumber);
        if (user == null) {
            log.warn("check user failed. phoneNumber: {}.", phoneNumber);
            throw new BusinessException("00000005","用户不在岗或没有手机号码与用户对应");
        }
        String dynamicCode = generateDynamicCode();
        log.info("dynamicCode: {}.", dynamicCode);
        try {
            // 存储动态码
            String key = authorityRedisMapper.setDyCode(plat, phoneNumber, dynamicCode);
            log.info("redis save: {},{}.",key, dynamicCode);

            String smsInfo = String.format(PassportMessageEnum.INWARD_TEMPLATE_MESSAGE.getTemplateMessage(), dynamicCode);
            String bizSrc = PassportMessageEnum.INWARD_TEMPLATE_MESSAGE.getBizSrc();
            String sysCode = PassportMessageEnum.INWARD_TEMPLATE_MESSAGE.getSysCode();

            // 发送短信
            String oaAccount = user.getUserName();
            String messageResult = smsVpcMapper.sendSms(oaAccount, smsInfo, bizSrc, sysCode);
            if (messageResult!=null && messageResult.equals(SUCCESS_CODE)) {
                log.info("send success.phoneNumber:{}, dynamicCode: {}, plat: {}.",oaAccount, dynamicCode, plat);
                response.setResult("");
            } else {
                log.error("send sms failed. phoneNumber:{}, dynamicCode:{}.", oaAccount, dynamicCode);
                log.info("will return code: {}.", dynamicCode);
                response.setResult(dynamicCode);
            }
            log.info("response: {}", JSON.toJSONString(response));
            return response;
        } catch (Exception e) {
            throw new BusinessException("00000002","send sms failed. "+e.toString());
        }
    }

    private String generateDynamicCode() {
        return RandomStringUtils.randomNumeric(6);
    }

    // PassportErrorCode.USER_AUTHENTICATE_FAILED
    // PassportErrorCode.DYNAMIC_CODE_VERIFICATION_COUNT_OUT_LIMIT
    @Override public LogOnDynamicCodeResponse logOnDynamicCode(LogOnDynamicCodeRequest req) {
        Integer plat = req.getPlat();
        String phoneNumber = req.getPhoneNumber();
        String dynamicCode = req.getDynamicCode();

        return logOnDynamicCode(phoneNumber, dynamicCode, plat);
    }

    @Override public LogOnDynamicCodeResponse logOnDynamicCode(String phoneNumber, String dynamicCode, Integer plat) {

        boolean checkResult;
        if (numbers.contains(phoneNumber) && TESTER_PASSWORD.equals(dynamicCode)) {
            // 测试账户判断
            log.info("no auth logon: {}, {}",plat, phoneNumber);
            checkResult = true;
        } else {
            checkResult = checkValid(plat, dynamicCode, phoneNumber);
        }
        if (! checkResult) {
            log.warn("login failed. phoneNumber: {},dynamicCode: {}, plat: {}.", phoneNumber, dynamicCode, plat);
            throw new BusinessException("00000002","用户验证失败");
        }
        UserEntity user = getUserFromPhone(phoneNumber);
        if (user == null) {
            log.warn("login failed. phoneNumber: {},dynamicCode: {}.", phoneNumber, dynamicCode);
            throw new BusinessException("00000005","用户不存在，没有手机号码与用户对应");
        }
        String accessTokenJson = buildAccessToken(plat, user.getMobile(), user.getUserName());

        LogOnDynamicCodeResponse response = new LogOnDynamicCodeResponse();
        response.setAccessTokenJson(accessTokenJson);
        return response;
    }

    @Override public LogOnDynamicCodeResponse logOnAccountCode(String username, String password, Integer plat) {

        boolean checkResult=false;
        if (numbers.contains(username) && TESTER_PASSWORD.equals(password)) {
            // 测试账户判断
            log.info("no auth logon: {}, {}",plat, username);
            checkResult = true;
        }
        UserEntity user = getUserFromUserName(username);
        if (user == null) {
            log.warn("login failed. username: {},password: {}.", username, password);
            throw new BusinessException("00000005","用户不存在，没有手机号码与用户对应");
        }
        if (! checkResult) {
            checkResult = checkAccountValid(plat, user.getPassword(), password);
            if(!checkResult) {
                log.warn("login failed. phoneNumber: {},dynamicCode: {}, plat: {}.", username, password, plat);
                throw new BusinessException("00000002", "用户验证失败");
            }
        }
        String accessTokenJson = buildAccessToken(plat, user.getMobile(), user.getUserName());

        LogOnDynamicCodeResponse response = new LogOnDynamicCodeResponse();
        response.setAccessTokenJson(accessTokenJson);
        return response;
    }

    @Override
    public LogOnDynamicCodeResponse logOnSSO(String username, Integer plat) {
        if (os_names.contains(username)) {
            // 测试账户判断
            log.info("no auth logon: {}, {}", plat, username);
        }
        UserEntity user = getUserFromUserName(username);
        if (user == null) {
            log.warn("login failed. username: {}", username);
            throw new BusinessException("00000005","用户不存在，没有手机号码与用户对应");
        }
        String accessTokenJson = buildAccessToken(plat, user.getMobile(), username);
        LogOnDynamicCodeResponse response = new LogOnDynamicCodeResponse();
        response.setAccessTokenJson(accessTokenJson);
        return response;
    }
    private String buildAccessToken(Integer plat, String phoneNumber, String username) {
        log.info("login success. phoneNumber: {}, username: {}.", phoneNumber, username);
        AccessToken accessToken = createToken(plat, phoneNumber);
        String accessTokenJson = JSON.toJSONString(accessToken);
        accessTokenRedisMapper2.setAccessToken(plat, phoneNumber, accessTokenJson);
        JSONObject json = new JSONObject();
        json.put("plat", plat);
        json.put("phoneNumber", phoneNumber);
        json.put("userID", username);
        accessTokenRedisMapper2.setTokenInfo(accessToken.getAccessToken(),json.toJSONString());
        return accessTokenJson;
    }

    @Override public String logOff(String accessToken) {
        return "success";
    }

    @Override public String getQRCode() {
        return generateDynamicCode();
    }

    @Override public LogOnQRCodeResult logOnQrCode(String content, String accessToken) {
        String qrCodeKey = generateQRCodeKey(content);

//        boolean valid = checkTokenValid(accessToken);
//        if (valid) {
//            redisClient.setStringEx(qrCodeKey, 600, accessToken); // 10分钟后自动删除
//            tokenService.addPlat(accessToken, Plat.WEB.getCode());
//        }
        return null;
    }

    @Override public String getToken(String content) {
        String qrCodeKey = generateQRCodeKey(content);

        String accessToken = "";//redisClient.getString(qrCodeKey);

        if (accessToken == null) {
            accessToken = StringUtils.EMPTY;
        }
        return accessToken;
    }

    private static final String QR_LOG_ON_KEY_PREFIX = "passport-internal.QRLogOn.";
    private String generateQRCodeKey(String content) {
        return QR_LOG_ON_KEY_PREFIX + content;
    }

    //
//    @Override public UserInfoResponse userInfo(UserInfoRequest req) {
//        String phoneNumber = req.getPhoneNumber();
//        log.info("userInfo by phoneNumber:{}.", phoneNumber);
//        UserInfoResponse response = new UserInfoResponse();
//        try {
//            // 根据手机号获取用户信息
//            UserEntity userEntity = new UserEntity();
//            userEntity.setEmail("lixiyong@hualala.com");
//            userEntity.setLoginName("lixiyong");
//            userEntity.setUserName("李锡永");
//            userEntity.setMobile("13811834706");
//            String userJson = JSON.toJSONString(userEntity);
//            response.setUserJson(userJson);
//            log.info("userInfo success. phoneNumber:{}, {}.", phoneNumber,userJson);
//            return response;
//        } catch (Exception e) {
//            response.setCode("00000004");
//            response.setMessage("验证码下发失败");
//            log.warn("userInfo failed. phoneNumber:{}.", phoneNumber);
//        }
//        return response;
//    }

    public boolean checkValid(Integer plat, String code, String phoneNumber) {

        String savedCode = authorityRedisMapper.getDyCode(plat, phoneNumber);

        // 由于验证码已包含数字和字母，所以修改此处对比规则（忽略大小写）
        if (code.equalsIgnoreCase(savedCode)) {
            authorityRedisMapper.delDyCode(plat, phoneNumber);
            return true;
        } else {
            return false;
        }
    }

    /**
     * 密码验证
     * @param plat 0
     * @param password0 库中保留密码
     * @param password 用户输入待验证密码
     * @return 成功-true
     */
    public boolean checkAccountValid(Integer plat, String password0, String password) {
        if (StringUtils.isEmpty(password0) || StringUtils.isEmpty(password)) {
            log.info("password is invalid.{}, {}.", password0, password);
            return false;
        }
        if(! password0.equals(password)) {
            return false;
        }
//        if(DEFAULT_PASSWORD.equals(password0)) {
//            throw new BusinessException("00000008", "请先使用手机号登录，然后重新设置密码。");
//        }
        return true;
    }

    private String generateTokenValue() {
        return UUID.randomUUID().toString();
    }
    private AccessToken createToken(Integer plat, String phoneNumber) {
        String tokenInfo = accessTokenRedisMapper2.getAccessToken(plat, phoneNumber);
        if (tokenInfo!=null) {
            return JSON.parseObject(tokenInfo, AccessToken.class);
        }
        String tokenValue = generateTokenValue();
        AccessToken accessToken = new AccessToken();
        accessToken.setAccessToken(tokenValue);
        accessToken.setExpiresIn(System.currentTimeMillis());
        return accessToken;
    }

    public UserEntity getUserFromPhone(String phoneNumber) {
        UserEntity entity = userMapper.selectUser(phoneNumber);
        if( entity==null) {
            log.info("user is not exist.");
        }
        return entity;
    }

    public UserEntity getUserFromUserName(String username) {
        UserEntity entity = userMapper.selectUserByUserName(username);
        if( entity==null) {
            log.info("user is not exist.");
        }
        return entity;
    }


    @Override public Long addUser(UserEntity entity) {
        log.info("set param: {}", JSON.toJSONString(entity));
        // 检查验证码是否有效
        boolean code = checkValid(0, entity.dynamicCode, entity.mobile);
        if (! code) {
            log.warn("add user check failed. mobile: {},dynamicCode: {}.", entity.mobile, entity.dynamicCode);
            throw new BusinessException("00000002","验证码无效");
        }
        // 检查用户是否存在
        UserEntity entity0 = userMapper.selectUser(entity.mobile);
        if( entity0!=null) {
            if(! entity0.userName.equals(entity.userName)) {
                log.info("mobile: {}, user: {} user0:{}", entity.mobile, entity.userName, entity0.userName);
                throw new BusinessException("00000003","手机号已经被绑定"+entity0.userName);
            }
            entity.id = entity0.id;
        }
        // 将用户信息写入
        Long retCode = 0L;
        if(entity.id==null || entity.id==0) {
            // 判断用户是否58用户 由于是内网使用暂时不需要判断用户
            log.info("will create user: {}", JSON.toJSONString(entity));
            entity.userNo = "U" + TimeUtil.currentTimeHllDT();
            retCode = userMapper.insertUser(entity);
        } else {
            log.warn("will update user: {}", JSON.toJSONString(entity));
            retCode = userMapper.updateUser(entity);
        }
        log.info("mapper code: {}.", retCode);
        // 发送邮件进行激活处理 status=2 激活后变为 status=1
        return retCode;
    }

}
